using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using JGLib.States;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input.Touch;

namespace TrafficTrouble.States
{
    public class DialogState : State
    {
        protected const float HIGHTLIGHT_FACTOR = .4f, DARKEN_FACTOR = .6f;
        protected Color DialogBackgroundColor { get { return Color.Black; } }
        protected Color DialogBorderColor { get { return Color.White; } }

        protected string DialogText { get; private set; }
        protected string[] ButtonText { get; private set; }
        protected Point DialogLoc { get; private set; }
        protected Point ButtonSize { get; private set; }
        protected Point[] ButtonLocs { get; private set; }
        protected Rectangle DialogRect { get; private set; }
        protected Rectangle[] ButtonRects { get; private set; }
        protected Vector2 DialogTextLoc { get; private set; }
        protected Vector2[] ButtonTextLocs { get; private set; }

        protected SpriteFont TextFont { get; private set; }

        protected Texture2D GameDarkening { get; private set; }
        protected Texture2D ButtonHighlight { get; private set; }
        protected Texture2D DialogBackground { get; private set; }
        protected Texture2D DialogBorder { get; private set; }

        //private int Width { get { return (int)(Game.Width * 3f/4f); } }
        //private int Height { get { return this.Width / 2; } }
        protected int Width { get; private set; }
        protected int Height { get; private set; }

        protected float ButtonToDialogHeightRatio { get; private set; }

        private int PressedButton = -1;

        protected GameState GameState { get; private set; }

        private int ButtonCount { get { return ButtonText.Length; } }

        public DialogState(object id, GraphicsDevice device, SpriteFont textFont, int width, int height,
            string dialogText, params string[] buttonText)
            : base(id)
        {
            this.GameDarkening = new Texture2D(device, 1, 1);
            this.GameDarkening.SetData<Color>(new Color[] { Color.White * DARKEN_FACTOR });

            this.ButtonHighlight = new Texture2D(device, 1, 1);
            this.ButtonHighlight.SetData<Color>(new Color[] { Color.White * HIGHTLIGHT_FACTOR });

            this.DialogBackground = new Texture2D(device, 1, 1);
            this.DialogBackground.SetData<Color>(new Color[] { DialogBackgroundColor });

            this.DialogBorder = new Texture2D(device, 1, 1);
            this.DialogBorder.SetData<Color>(new Color[] { DialogBorderColor });

            this.TextFont = textFont;
            this.DialogText = dialogText;
            this.ButtonText = buttonText;
            this.Width = width;
            this.Height = height;

            int dialogTextLines = dialogText.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries).Length;
            this.ButtonToDialogHeightRatio = 1f / (dialogTextLines + 1);

            this.ComputeLocs();
        }

        protected override void GetSwitchedTo(object prevStateID, object[] data)
        {
            if ((Type)prevStateID == typeof(GameState))
                this.GameState = (GameState)data[0];
        }

        private void ComputeLocs()
        {
            this.ButtonLocs = new Point[this.ButtonCount];
            this.ButtonRects = new Rectangle[this.ButtonCount];
            this.ButtonTextLocs = new Vector2[this.ButtonCount];

            Point size = new Point(this.Width, this.Height);
            this.ButtonSize = new Point(size.X / this.ButtonCount, (int)(size.Y * this.ButtonToDialogHeightRatio));

            this.DialogLoc = new Point((Game.Width - size.X) / 2, (Game.Height - size.Y) / 2);
            this.DialogRect = new Rectangle(this.DialogLoc.X, this.DialogLoc.Y, size.X, size.Y);
            Vector2 dialogTextSize = this.TextFont.MeasureString(this.DialogText);
            this.DialogTextLoc = new Vector2(this.DialogLoc.X, this.DialogLoc.Y)
                + (new Vector2(this.Width, this.Height - this.ButtonSize.Y) - dialogTextSize) / 2f;
            
            Vector2[] textSizes = new Vector2[this.ButtonCount];
            for (int button = 0; button < this.ButtonCount; button++)
            {
                this.ButtonLocs[button] = new Point(this.DialogLoc.X + button * this.ButtonSize.X,
                    this.DialogLoc.Y + (this.Height - this.ButtonSize.Y));

                this.ButtonRects[button] = new Rectangle(this.ButtonLocs[button].X, this.ButtonLocs[button].Y,
                    this.ButtonSize.X, this.ButtonSize.Y);

                textSizes[button] = this.TextFont.MeasureString(this.ButtonText[button]);
                this.ButtonTextLocs[button] = new Vector2(this.ButtonLocs[button].X, this.ButtonLocs[button].Y)
                    + (new Vector2(this.ButtonSize.X, this.ButtonSize.Y) - textSizes[button]) / 2f;
            }
        }

        protected override void Update(double gameTime)
        {
            foreach (TouchLocation touch in Touch.Touches)
            {
                int buttonOver = -1;

                for (int button = 0; button < this.ButtonCount; button++)
                {
                    if (this.ButtonRects[button].Contains(touch.Position))
                    {
                        buttonOver = button;
                        break;
                    }
                }

                if (touch.State == TouchLocationState.Pressed)
                    this.PressedButton = buttonOver;
                else if (touch.State == TouchLocationState.Moved && buttonOver != this.PressedButton)
                    this.PressedButton = -1;
                else if (touch.State == TouchLocationState.Released
                     && this.PressedButton != -1 && this.PressedButton == buttonOver)
                {
                    this.PressedButton = -1;
                    this.SwitchToState(typeof(GameState), buttonOver);
                }
            }

            base.Update(gameTime);
        }

        protected override void Draw(SpriteBatch g)
        {
            this.GameState.Draw(g, this);

            g.Draw(this.GameDarkening, new Rectangle(0, 0, Game.Width, Game.Height), Color.White);

            g.Draw(this.DialogBackground, this.DialogRect, Color.White);

            if (this.PressedButton != -1)
                g.Draw(this.ButtonHighlight, this.ButtonRects[this.PressedButton], Color.White);

            g.Draw(this.DialogBorder, new Rectangle(this.DialogLoc.X, this.DialogLoc.Y, 1, this.Height), Color.White);
            g.Draw(this.DialogBorder, new Rectangle(this.DialogLoc.X, this.DialogLoc.Y, this.Width, 1), Color.White);
            g.Draw(this.DialogBorder, new Rectangle(this.DialogLoc.X, this.DialogLoc.Y + this.Height - 1,
                this.Width, 1), Color.White);
            g.Draw(this.DialogBorder, new Rectangle(this.DialogLoc.X + this.Width - 1, this.DialogLoc.Y,
                1, this.Height), Color.White);

            g.Draw(this.DialogBorder, new Rectangle(this.ButtonLocs[0].X, this.ButtonLocs[0].Y, this.Width, 1), Color.White);
            for (int button = 1; button < this.ButtonCount; button++)
                g.Draw(this.DialogBorder,
                    new Rectangle(this.ButtonLocs[button].X, this.ButtonLocs[button].Y, 1, this.ButtonSize.Y), Color.White);

            g.DrawString(this.TextFont, this.DialogText, this.DialogTextLoc, Color.White);
            for (int button = 0; button < this.ButtonCount; button++)
                g.DrawString(this.TextFont, this.ButtonText[button], this.ButtonTextLocs[button], Color.White);
        }
    }
}
